package com.apes.fn.business.fixedLoss.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.modle.LossReceivedApportion;
import com.apes.fn.business.fixedLoss.modle.LossReceivedItem;
import com.apes.fn.business.fixedLoss.repository.LossQuotationDao;
import com.apes.fn.business.fixedLoss.repository.LossQuotationRepository;
import com.apes.fn.business.fixedLoss.repository.LossReceivedApportionRepository;
import com.apes.fn.business.fixedLoss.repository.LossReceivedItemRepository;
import com.apes.fn.scm.lossSale.LossSaleAdjust;
import com.apes.fn.scm.lossSale.LossSaleAdjustPayment;
import com.apes.fn.scm.lossSale.LossSaleAdjustPaymentRepository;
import com.apes.fn.scm.lossSale.LossSaleAdjustRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderPayMethod;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.repository.SequenceRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.swing.*;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @program: apes-server
 * @description:
 * @author: czs
 * @create: 2022-08-02 14:13
 **/
@Component("lossReceivedItemService")
public class LossReceivedItemService extends DomainService {

    @Autowired
    private LossQuotationRepository lossQuotationRepository;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private SequenceRepository sequenceRepository;
    @Autowired
    private LossReceivedItemRepository lossReceivedItemRepository;
    @Autowired
    private LossReceivedApportionRepository lossReceivedApportionRepository;
    @Autowired
    private LossQuotationDao lossQuotationDao;
    @Autowired
    private LossReceivedApportionService lossReceivedApportionService;

    private LossQuotation createReceivedItem(SimpleRequest request){
        JSONObject jo = request.getJO();
        //生成到账明细
        LossReceivedItem lossReceivedItem = generateItem(request);

        //创建待缴款单-改为分摊后发起
//        createToPrepare(lossReceivedItem,lossReceivedItem.getLossQuotation().getFixedLossDept());
        return lossReceivedItem.getLossQuotation();
    }

    private LossReceivedItem generateItem(SimpleRequest request) {
        JSONObject jo = request.getJO();
        JSONObject serialNumber = jo.getJSONObject("serialNumber");
        double receivedAmount = jo.getDoubleValue("receivedAmount");
        double unReceivedAmount = jo.getDoubleValue("unReceivedAmount");
        double minReceivedAmount = jo.getDoubleValue("minReceivedAmount");
        if (receivedAmount>unReceivedAmount)throw new RuntimeException("回款金额不能大于待回款金额:"+unReceivedAmount);
        if (serialNumber!=null && receivedAmount>serialNumber.getDoubleValue("receiptAmount"))throw new RuntimeException("回款金额不能大于流水金额:"+serialNumber.getDoubleValue("receiptAmount"));
        if (receivedAmount<minReceivedAmount)throw new RuntimeException("回款金额不能小于已回款金额:"+minReceivedAmount);

        LossQuotation lossQuotation = lossQuotationRepository.findOne(jo.getString("id"));
        LossReceivedItem lossReceivedItem = new LossReceivedItem();
        lossReceivedItem.setId(idGenerate());
        lossReceivedItem.setOperator(((PartyRole)request.getPerson()).getName());
        lossReceivedItem.setRemark(jo.getString("remark"));
        lossReceivedItem.setReceivedAmount(receivedAmount);
        Enumeration accountType = enumerationRepository.findOne(Optional.ofNullable(jo.getJSONObject("accountType")).orElseGet(JSONObject::new).getString("id"));
        lossReceivedItem.setAccountType(accountType);
        lossReceivedItem.setReceivedDate(jo.getDate("receivedDate"));
        lossReceivedItem.setSerialNumber(Optional.ofNullable(serialNumber).orElseGet(JSONObject::new).getString("transactionFlowNum"));
        List<LossReceivedItem> lossReceivedItemList = lossQuotation.getLossReceivedItem();
        lossReceivedItemList.add(lossReceivedItem);
        lossQuotation.setLossReceivedItem(lossReceivedItemList);
        //更新定损到账状态
        lossQuotation.updateReceivedState();

        lossQuotationRepository.saveAndFlush(lossQuotation);
        //通知流水号
        if (lossReceivedItem.getSerialNumber()!=null)
            this.invoke("fn.transactionFlow.byGenerateLossReceivedItem",lossReceivedItem);

        return lossReceivedItem;
    }

    private String idGenerate(){
        String receivedItemId = sequenceRepository.findAll("SELECT IR_SEQUENCE_0" + sequenceRepository.findFirstByCodeOrderByCodeAsc("ser_loss_received_item").getId() + ".NEXTVAL FROM DUAL ").get(0).toString();
        StringBuffer sf = new StringBuffer();
        if (receivedItemId.length()<4) {
            int pi = 4 - receivedItemId.length();
            for (int i = 0; i < pi; i++) {
                sf.append("0");
            }
        }else {
            return receivedItemId;
        }
        return sf.toString() + receivedItemId;
    }

    private void test(SimpleRequest request){
        LossReceivedItem lossReceivedItem = lossReceivedItemRepository.findOne((String) request.get("id"));
        this.invoke("fn.transactionFlow.byGenerateLossReceivedItem",lossReceivedItem);
    }


    @OutboxSubscriber(id="fn.lossQuotation.retailReceived", name="定损单到账")
    public void retailReceived(OutboxPayloadWrapper wrapper){
        JSONObject param = JSONObject.parseObject(wrapper.getPayload());

        String id = param.getString("id");
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(id);
        SpringManager.getBean(LossReceivedItemService.class).createReceivedItem(retailOrder.getSource(),retailOrder.getPaymentMethodSet());
    }

    private void testRetailReceived(SimpleRequest request){
        testRetailReceivedDT(request);
    }

    private void testRetailReceivedDT(SimpleRequest request){
        JSONObject jo = request.getJO();
        String id = jo.getString("id");
        LossSaleAdjust lossSaleAdjust = SpringManager.getBean(LossSaleAdjustRepository.class).findOne(id);
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findByOrigin(id);

        SpringManager.getBean(LossReceivedItemService.class).createReceivedItem(lossSaleAdjust.getLossQuotationId(),retailOrder.getPaymentMethodSet());

//        createReceivedItem(retailOrder.getSource(),retailOrder.getPaymentMethodSet());
    }

    public LossQuotation createReceivedItem(String lossQuotationId, Set<RetailOrderPayMethod> paymentMethodSet){
        LossQuotation lossQuotation = lossQuotationRepository.findOne(lossQuotationId);
        RetailOrder retailOrder = paymentMethodSet.stream().findAny().get().getOrder();
        String source = retailOrder.getOrigin();
        paymentMethodSet.forEach(retailOrderPayMethod -> createReceivedItem(lossQuotation, retailOrderPayMethod));
        //先写负分摊明细
        List<LossReceivedItem> lossReceivedItems = lossReceivedItemRepository.findAll(JpaDsl.toCriteria("sourceFrom", "EQ", source));
        double unappropriatedAmount = lossReceivedItems.stream().filter(lossReceivedItem -> lossReceivedItem.getReceivedAmount() > 0).mapToDouble(LossReceivedItem::getReceivedAmount).sum();
        List<LossReceivedItem> lossReceivedItemList = lossReceivedItems.stream().filter(lossReceivedItem -> lossReceivedItem.getReceivedAmount() < 0).collect(Collectors.toList());
        for (int i = 0; i < lossReceivedItemList.size(); i++) {
            LossReceivedItem lossReceivedItem = lossReceivedItemList.get(i);
            double a = i==lossReceivedItemList.size()-1?unappropriatedAmount :0;
            if (lossReceivedItem.getReceivedAmount()<0){
                if (lossReceivedItem.getAccountType().getId().equals("002033")) {
                    //todo 需要终止待缴款单
                }
                LossReceivedApportion lossReceivedApportion = new LossReceivedApportion();
                lossReceivedApportion.setLossReceivedItem(lossReceivedItem);
                lossReceivedApportion.setLossQuotationId(lossQuotation.getId());
                lossReceivedApportion.setReceivedDate(new Date());
                lossReceivedApportion.setNeedApportionAmount(lossReceivedItem.getReceivedAmount());
                lossReceivedApportion.setUnappropriatedAmount(a);
                lossReceivedApportion.setApportionOrder(retailOrder.getId());
                lossReceivedApportion.setApportionOrderType(retailOrder.getInnerBusinessType());
                lossReceivedApportion.setApportionAmount(lossReceivedItem.getReceivedAmount());
                if (a==0)lossReceivedApportion.setFinish(true);
                lossReceivedApportionService.create(lossReceivedApportion);
                lossReceivedItem.setApportionComplete(true);
                lossReceivedItemRepository.saveAndFlush(lossReceivedItem);
            }
        }

        lossQuotation.updateReceivedState();

        lossQuotationRepository.saveAndFlush(lossQuotation);
        return lossQuotation;
    }


    public LossQuotation createReceivedItem(String lossQuotationId, RetailOrderPayMethod retailOrderPayMethod){
        LossQuotation lossQuotation = lossQuotationRepository.findOne(lossQuotationId);

        lossQuotation = createReceivedItem(lossQuotation, retailOrderPayMethod);
        lossQuotation.updateReceivedState();

        return lossQuotationRepository.saveAndFlush(lossQuotation);
    }

    public LossQuotation createReceivedItem(LossQuotation lossQuotation, RetailOrderPayMethod retailOrderPayMethod){
        if (retailOrderPayMethod.getPaymentMethodType().getId().equals("09"))return lossQuotation;
        RetailOrder order = retailOrderPayMethod.getOrder();
        LossReceivedItem lossReceivedItem = new LossReceivedItem();
        lossReceivedItem.setReceivedAmount(retailOrderPayMethod.getAmount());
        lossReceivedItem.setReceivedDate(new Date());
        lossReceivedItem.setSourceFrom(order.getOrigin());
        lossReceivedItem.setSourceBusinessType(order.getSourceBusinessType());
        lossReceivedItem.setLossQuotation(lossQuotation);
        //收款方式为现金时到账记录写到账(002033)门店私户 否则为(002031)平台公户
        if (retailOrderPayMethod.getPaymentMethodType().getId().equals("01")) {
            lossReceivedItem.setAccountType(enumerationRepository.findOne("002033"));
        }else {
            lossReceivedItem.setAccountType(enumerationRepository.findOne("002031"));
        }

        List<LossReceivedItem> lossReceivedItemList = lossQuotation.getLossReceivedItem();
        lossReceivedItemList.add(lossReceivedItemRepository.saveAndFlush(lossReceivedItem));
        lossQuotation.setLossReceivedItem(lossReceivedItemList);

        return lossQuotation;
    }

    private JSONArray queryCarAccidentReceivedInfo(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONArray jsonArray = lossQuotationDao.queryLossReceivedItemInfo(jo);
        return jsonArray;
    }
}
